@@ -1,7 +1,7 @@  | 
            ||
| 1 | 1 | 
                github "Yalantis/PullToRefresh"  | 
            
| 2 | 
                -github "ReactiveX/RxSwift" ~> 4.3  | 
            |
| 2 | 
                +github "ReactiveX/RxSwift"  | 
            |
| 3 | 3 | 
                github "onevcat/Kingfisher" ~> 5.0  | 
            
| 4 | 
                -github "Alamofire/Alamofire" "5.0.0.beta.1"  | 
            |
| 4 | 
                +github "Alamofire/Alamofire" "5.0.0-beta.3"  | 
            |
| 5 | 5 | 
                github "stephencelis/SQLite.swift" ~> 0.11.5  | 
            
| 6 | 6 | 
                github "tristanhimmelman/ObjectMapper" ~> 3.4  | 
            
| 7 | 7 | 
                github "RxSwiftCommunity/RxDataSources" ~> 3.0  | 
            
                @@ -1,7 +1,7 @@  | 
            ||
| 1 | 
                -github "Alamofire/Alamofire" "5.0.0.beta.1"  | 
            |
| 1 | 
                +github "Alamofire/Alamofire" "5.0.0-beta.3"  | 
            |
| 2 | 2 | 
                github "ReactiveX/RxSwift" "4.4.2"  | 
            
| 3 | 3 | 
                github "RxSwiftCommunity/RxDataSources" "3.1.0"  | 
            
| 4 | 4 | 
                github "Yalantis/PullToRefresh" "3.1"  | 
            
| 5 | 
                -github "onevcat/Kingfisher" "5.2.0"  | 
            |
| 5 | 
                +github "onevcat/Kingfisher" "5.3.1"  | 
            |
| 6 | 6 | 
                github "stephencelis/SQLite.swift" "0.11.5"  | 
            
| 7 | 7 | 
                github "tristanhimmelman/ObjectMapper" "3.4.2"  | 
            
                @@ -507,7 +507,7 @@  | 
            ||
| 507 | 507 | 
                 		A69FFA9E1E7004700006FEE0 /* PhotoDetailCommentCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoDetailCommentCell.swift; sourceTree = "<group>"; };
               | 
            
| 508 | 508 | 
                 		A69FFAA31E7004700006FEE0 /* PhotoDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoDetailViewController.swift; sourceTree = "<group>"; };
               | 
            
| 509 | 509 | 
                 		A69FFAA41E7004700006FEE0 /* PhotoDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoDetailViewModel.swift; sourceTree = "<group>"; };
               | 
            
| 510 | 
                -		A69FFAA61E7004700006FEE0 /* ImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCell.swift; sourceTree = "<group>"; wrapsLines = 0; };
               | 
            |
| 510 | 
                +		A69FFAA61E7004700006FEE0 /* ImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCell.swift; sourceTree = "<group>"; usesTabs = 0; wrapsLines = 1; };
               | 
            |
| 511 | 511 | 
                 		A69FFAA81E7004700006FEE0 /* ShareController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareController.swift; sourceTree = "<group>"; };
               | 
            
| 512 | 512 | 
                 		A69FFAA91E7004700006FEE0 /* PhotoPreviewViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoPreviewViewController.swift; sourceTree = "<group>"; };
               | 
            
| 513 | 513 | 
                 		A69FFAAB1E7004700006FEE0 /* GroupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupViewController.swift; sourceTree = "<group>"; };
               | 
            
                @@ -1489,6 +1489,7 @@  | 
            ||
| 1489 | 1489 | 
                developmentRegion = English;  | 
            
| 1490 | 1490 | 
                hasScannedForEncodings = 0;  | 
            
| 1491 | 1491 | 
                knownRegions = (  | 
            
| 1492 | 
                + English,  | 
            |
| 1492 | 1493 | 
                en,  | 
            
| 1493 | 1494 | 
                Base,  | 
            
| 1494 | 1495 | 
                global,  | 
            
                @@ -158,15 +158,15 @@ class NetworkApi {
               | 
            ||
| 158 | 158 | 
                }  | 
            
| 159 | 159 | 
                 | 
            
| 160 | 160 | 
                //extension request retrier  | 
            
| 161 | 
                -extension NetworkApi {
               | 
            |
| 162 | 
                -    public struct OAuthHandler: RequestRetrier {
               | 
            |
| 163 | 
                -        init() {}
               | 
            |
| 164 | 
                -        public func should(_ manager: Session, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
               | 
            |
| 165 | 
                -            if let response = request.response, response.statusCode == 401 {
               | 
            |
| 166 | 
                - completion(true, 1.0) // 1秒后重试  | 
            |
| 167 | 
                -            } else {
               | 
            |
| 168 | 
                - completion(false, 0.0) // 不重连  | 
            |
| 169 | 
                - }  | 
            |
| 170 | 
                - }  | 
            |
| 171 | 
                - }  | 
            |
| 172 | 
                -}  | 
            |
| 161 | 
                +//extension NetworkApi {
               | 
            |
| 162 | 
                +//    public struct OAuthHandler: RequestRetrier {
               | 
            |
| 163 | 
                +//        init() {}
               | 
            |
| 164 | 
                +//        public func should(_ manager: Session, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
               | 
            |
| 165 | 
                +//            if let response = request.response, response.statusCode == 401 {
               | 
            |
| 166 | 
                +// completion(true, 1.0) // 1秒后重试  | 
            |
| 167 | 
                +//            } else {
               | 
            |
| 168 | 
                +// completion(false, 0.0) // 不重连  | 
            |
| 169 | 
                +// }  | 
            |
| 170 | 
                +// }  | 
            |
| 171 | 
                +// }  | 
            |
| 172 | 
                +//}  | 
            
                @@ -13,6 +13,11 @@ import PaiaiUIKit  | 
            ||
| 13 | 13 | 
                 final class ImageCell: UICollectionViewCell, UIScrollViewDelegate {
               | 
            
| 14 | 14 | 
                @IBOutlet weak var scrollView: UIScrollView!  | 
            
| 15 | 15 | 
                var photoImage = UIImageView()  | 
            
| 16 | 
                +  | 
            |
| 17 | 
                + private var angle: CGFloat = 0  | 
            |
| 18 | 
                + private var scale: CGFloat = 1  | 
            |
| 19 | 
                + private var scaleRatio: CGFloat = 1  | 
            |
| 20 | 
                + private var aspectFitSize = CGSize.zero  | 
            |
| 16 | 21 | 
                 | 
            
| 17 | 22 | 
                     func setModel(url: String) {
               | 
            
| 18 | 23 | 
                photoImage.frame = CGRect(x: 0, y: 0, width: width, height: height)  | 
            
                @@ -57,9 +62,44 @@ final class ImageCell: UICollectionViewCell, UIScrollViewDelegate {
               | 
            ||
| 57 | 62 | 
                scrollView.zoom(to: zoomRect, animated: true)  | 
            
| 58 | 63 | 
                }  | 
            
| 59 | 64 | 
                }  | 
            
| 60 | 
                -  | 
            |
| 65 | 
                +  | 
            |
| 61 | 66 | 
                     override func prepareForReuse() {
               | 
            
| 62 | 67 | 
                super.prepareForReuse()  | 
            
| 63 | 68 | 
                scrollView.zoomScale = 1  | 
            
| 69 | 
                + clearRotation()  | 
            |
| 70 | 
                + }  | 
            |
| 71 | 
                +  | 
            |
| 72 | 
                +    func rotate() {
               | 
            |
| 73 | 
                + if let imageSize = photoImage.image?.size,  | 
            |
| 74 | 
                +            aspectFitSize == CGSize.zero {
               | 
            |
| 75 | 
                + let ratio = size.width / imageSize.width  | 
            |
| 76 | 
                + aspectFitSize = CGSize(width: size.width, height: ratio * imageSize.height)  | 
            |
| 77 | 
                + scaleRatio = size.width / aspectFitSize.height  | 
            |
| 78 | 
                + }  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                + let animation1 = CABasicAnimation(keyPath: "transform.rotation.z")  | 
            |
| 81 | 
                + animation1.fromValue = angle  | 
            |
| 82 | 
                + animation1.toValue = angle + CGFloat.pi * 0.5  | 
            |
| 83 | 
                +  | 
            |
| 84 | 
                + let animation2 = CABasicAnimation(keyPath: "transform.scale")  | 
            |
| 85 | 
                + let (toScale, fromScale) = scale == 1 ? (scaleRatio, 1) : (1, scaleRatio)  | 
            |
| 86 | 
                + animation2.fromValue = CGPoint(x: fromScale, y: fromScale)  | 
            |
| 87 | 
                + animation2.toValue = CGPoint(x: toScale, y: toScale)  | 
            |
| 88 | 
                +  | 
            |
| 89 | 
                +  | 
            |
| 90 | 
                + let animationGroup = CAAnimationGroup()  | 
            |
| 91 | 
                + animationGroup.animations = [animation1, animation2]  | 
            |
| 92 | 
                + animationGroup.duration = 0.5  | 
            |
| 93 | 
                + animationGroup.fillMode = .forwards  | 
            |
| 94 | 
                + animationGroup.isRemovedOnCompletion = false  | 
            |
| 95 | 
                + photoImage.layer.add(animationGroup, forKey: "")  | 
            |
| 96 | 
                +  | 
            |
| 97 | 
                + angle += CGFloat.pi * 0.5  | 
            |
| 98 | 
                + scale = toScale  | 
            |
| 99 | 
                + }  | 
            |
| 100 | 
                +  | 
            |
| 101 | 
                +    func clearRotation() {
               | 
            |
| 102 | 
                + angle = 0  | 
            |
| 103 | 
                + scale = 1  | 
            |
| 64 | 104 | 
                }  | 
            
| 65 | 105 | 
                }  | 
            
                @@ -54,6 +54,7 @@ final class PhotoPreviewViewController: UIViewController {
               | 
            ||
| 54 | 54 | 
                Toast.show(message: "已保存照片到相册中", image: UIImage(named: "icon-success"))  | 
            
| 55 | 55 | 
                }  | 
            
| 56 | 56 | 
                }  | 
            
| 57 | 
                + var angle: CGFloat = 0  | 
            |
| 57 | 58 | 
                }  | 
            
| 58 | 59 | 
                 | 
            
| 59 | 60 | 
                /// binding  | 
            
                @@ -100,22 +101,7 @@ extension PhotoPreviewViewController {
               | 
            ||
| 100 | 101 | 
                         guard let cell = collectionView.cellForItem(at: IndexPath(item: viewModel.currIndex, section: 0)) as? ImageCell else {
               | 
            
| 101 | 102 | 
                return  | 
            
| 102 | 103 | 
                }  | 
            
| 103 | 
                -        UIView.beginAnimations("image.rotate", context: nil)
               | 
            |
| 104 | 
                -        UIView.animate(withDuration: 0.5) {
               | 
            |
| 105 | 
                - let image = cell.photoImage.image  | 
            |
| 106 | 
                -            switch image?.imageOrientation.rawValue {
               | 
            |
| 107 | 
                - case .some(0):  | 
            |
| 108 | 
                - cell.photoImage.image = UIImage(cgImage: (image?.cgImage)!, scale: UIScreen.main.scale, orientation: UIImage.Orientation.right)  | 
            |
| 109 | 
                - case .some(1):  | 
            |
| 110 | 
                - cell.photoImage.image = UIImage(cgImage: (image?.cgImage)!, scale: UIScreen.main.scale, orientation: UIImage.Orientation.left)  | 
            |
| 111 | 
                - case .some(2):  | 
            |
| 112 | 
                - cell.photoImage.image = UIImage(cgImage: (image?.cgImage)!, scale: UIScreen.main.scale, orientation: UIImage.Orientation.up)  | 
            |
| 113 | 
                - case .some(3):  | 
            |
| 114 | 
                - cell.photoImage.image = UIImage(cgImage: (image?.cgImage)!, scale: UIScreen.main.scale, orientation: UIImage.Orientation.down)  | 
            |
| 115 | 
                - default:  | 
            |
| 116 | 
                - break  | 
            |
| 117 | 
                - }  | 
            |
| 118 | 
                - }  | 
            |
| 104 | 
                + cell.rotate()  | 
            |
| 119 | 105 | 
                }  | 
            
| 120 | 106 | 
                 | 
            
| 121 | 107 | 
                     @IBAction func download(_ sender: UIButton) {
               |